package com.supermarket.service;

import com.supermarket.entity.ArticleComment;
import com.supermarket.entity.User;
import com.supermarket.exception.ArticleException;
import com.supermarket.mapper.ArticleCommentMapper;
import com.supermarket.mapper.ArticleMapper;
import com.supermarket.mapper.UserMapper;
import com.supermarket.common.RedisUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ArticleCommentService {

    @Resource
    private ArticleCommentMapper articleCommentMapper;

    @Resource
    private ArticleMapper articleMapper;

    @Resource
    private UserMapper userMapper;
    
    @Resource
    private RedisUtil redisUtil;
    
    // Redis缓存相关的Key前缀
    private static final String ARTICLE_COMMENT_KEY = "article:comment:";
    private static final String ARTICLE_ROOT_COMMENT_KEY = "article:rootcomment:";
    private static final String ARTICLE_COMMENT_COUNT_KEY = "article:comment:count:";
    private static final String ARTICLE_COMMENT_TREE_KEY = "article:comment:tree:";
    private static final int ARTICLE_COMMENT_CACHE_SECONDS = 1800; // 评论缓存默认30分钟

    /**
     * 添加评论
     *
     * @param comment 评论对象
     * @return 添加成功的评论ID
     */
    @Transactional
    public Integer addComment(ArticleComment comment) {
        // 验证文章是否存在
        if (articleMapper.selectArticleById(comment.getArticleId()) == null) {
            throw new ArticleException("文章不存在");
        }

        // 验证用户是否存在
        if (userMapper.selectUserById(comment.getUserId()) == null) {
            throw new ArticleException("用户不存在");
        }

        // 如果是回复，验证父评论是否存在
        if (comment.getParentId() != null && comment.getParentId() > 0) {
            ArticleComment parentComment = articleCommentMapper.selectCommentById(comment.getParentId());
            if (parentComment == null) {
                throw new ArticleException("要回复的评论不存在");
            }
            // 确保回复的是同一篇文章的评论
            if (!parentComment.getArticleId().equals(comment.getArticleId())) {
                throw new ArticleException("不能跨文章回复评论");
            }
        }

        articleCommentMapper.insertComment(comment);
        
        // 清除相关缓存
        clearArticleCommentCache(comment.getArticleId(), comment.getId(), comment.getParentId());
        
        return comment.getId();
    }

    /**
     * 删除评论
     *
     * @param id 评论ID
     * @return 影响的行数
     */
    @Transactional
    public int deleteComment(Integer id) {
        // 先获取当前评论，检查是否存在
        ArticleComment comment = articleCommentMapper.selectCommentById(id);
        if (comment == null) {
            throw new ArticleException("评论不存在");
        }
        
        Integer articleId = comment.getArticleId();

        // 先删除此评论的所有回复
        List<ArticleComment> replies = articleCommentMapper.selectRepliesByParentId(id);
        for (ArticleComment reply : replies) {
            articleCommentMapper.deleteComment(reply.getId());
        }

        // 删除评论本身
        int result = articleCommentMapper.deleteComment(id);
        
        // 清除相关缓存
        clearArticleCommentCache(articleId, id, comment.getParentId());
        
        return result;
    }

    /**
     * 获取评论详情
     *
     * @param id 评论ID
     * @return 评论对象
     */
    public ArticleComment getCommentById(Integer id) {
        String cacheKey = ARTICLE_COMMENT_KEY + "id:" + id;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (ArticleComment) cached;
        }
        
        // 缓存未命中，查询数据库
        ArticleComment comment = articleCommentMapper.selectCommentById(id);
        
        // 将结果存入缓存
        if (comment != null) {
            redisUtil.set(cacheKey, comment, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return comment;
    }

    /**
     * 获取文章所有评论
     *
     * @param articleId 文章ID
     * @return 评论列表
     */
    public List<ArticleComment> getCommentsByArticleId(Integer articleId) {
        String cacheKey = ARTICLE_COMMENT_KEY + "article:" + articleId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleComment>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<ArticleComment> comments = articleCommentMapper.selectCommentsByArticleId(articleId);
        
        // 将结果存入缓存
        if (comments != null && !comments.isEmpty()) {
            redisUtil.set(cacheKey, comments, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return comments;
    }

    /**
     * 获取用户所有评论
     *
     * @param userId 用户ID
     * @return 评论列表
     */
    public List<ArticleComment> getCommentsByUserId(Integer userId) {
        String cacheKey = ARTICLE_COMMENT_KEY + "user:" + userId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleComment>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<ArticleComment> comments = articleCommentMapper.selectCommentsByUserId(userId);
        
        // 将结果存入缓存
        if (comments != null && !comments.isEmpty()) {
            redisUtil.set(cacheKey, comments, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return comments;
    }

    /**
     * 获取评论的回复
     *
     * @param parentId 父评论ID
     * @return 回复列表
     */
    public List<ArticleComment> getRepliesByParentId(Integer parentId) {
        String cacheKey = ARTICLE_COMMENT_KEY + "replies:" + parentId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleComment>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<ArticleComment> replies = articleCommentMapper.selectRepliesByParentId(parentId);
        
        // 将结果存入缓存
        if (replies != null && !replies.isEmpty()) {
            redisUtil.set(cacheKey, replies, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return replies;
    }

    /**
     * 统计文章评论数
     *
     * @param articleId 文章ID
     * @return 评论数量
     */
    public int countCommentsByArticleId(Integer articleId) {
        String cacheKey = ARTICLE_COMMENT_COUNT_KEY + articleId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (int) cached;
        }
        
        // 缓存未命中，查询数据库
        int count = articleCommentMapper.countCommentsByArticleId(articleId);
        
        // 将结果存入缓存
        redisUtil.set(cacheKey, count, ARTICLE_COMMENT_CACHE_SECONDS);
        
        return count;
    }

    /**
     * 获取文章的一级评论
     *
     * @param articleId 文章ID
     * @return 一级评论列表
     */
    public List<ArticleComment> getRootCommentsByArticleId(Integer articleId) {
        String cacheKey = ARTICLE_ROOT_COMMENT_KEY + articleId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<ArticleComment>) cached;
        }
        
        // 缓存未命中，查询数据库
        List<ArticleComment> rootComments = articleCommentMapper.selectRootCommentsByArticleId(articleId);
        
        // 将结果存入缓存
        if (rootComments != null && !rootComments.isEmpty()) {
            redisUtil.set(cacheKey, rootComments, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return rootComments;
    }

    /**
     * 分页查询文章评论
     *
     * @param articleId 文章ID
     * @param pageNum   当前页码
     * @param pageSize  每页显示条数
     * @return 包含分页结果的 Map
     */
    public Map<String, Object> getCommentsWithPagination(Integer articleId, int pageNum, int pageSize) {
        String cacheKey = ARTICLE_COMMENT_KEY + "page:" + articleId + ":" + pageNum + ":" + pageSize;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<String, Object>) cached;
        }
        
        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;
        
        // 获取评论列表
        List<ArticleComment> comments = articleCommentMapper.selectCommentsByArticleIdWithPagination(
                articleId, offset, pageSize);
        
        // 获取总数
        int total = countCommentsByArticleId(articleId);
        
        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("list", comments);
        result.put("total", total);
        
        // 将结果存入缓存
        redisUtil.set(cacheKey, result, ARTICLE_COMMENT_CACHE_SECONDS);
        
        return result;
    }

    /**
     * 构建评论树（带用户信息）
     *
     * @param articleId 文章ID
     * @return 评论树
     */
    public List<Map<String, Object>> getCommentTree(Integer articleId) {
        String cacheKey = ARTICLE_COMMENT_TREE_KEY + articleId;
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (List<Map<String, Object>>) cached;
        }
        
        // 获取一级评论
        List<ArticleComment> rootComments = getRootCommentsByArticleId(articleId);
        List<Map<String, Object>> result = new ArrayList<>();
        
        for (ArticleComment rootComment : rootComments) {
            Map<String, Object> commentMap = buildCommentMap(rootComment);
            
            // 获取评论的回复
            List<ArticleComment> replies = getRepliesByParentId(rootComment.getId());
            List<Map<String, Object>> replyList = new ArrayList<>();
            
            for (ArticleComment reply : replies) {
                replyList.add(buildCommentMap(reply));
            }
            
            commentMap.put("replies", replyList);
            result.add(commentMap);
        }
        
        // 将结果存入缓存
        if (!result.isEmpty()) {
            redisUtil.set(cacheKey, result, ARTICLE_COMMENT_CACHE_SECONDS);
        }
        
        return result;
    }
    
    /**
     * 构建评论Map
     *
     * @param comment 评论对象
     * @return 带用户信息的评论Map
     */
    private Map<String, Object> buildCommentMap(ArticleComment comment) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", comment.getId());
        map.put("articleId", comment.getArticleId());
        map.put("content", comment.getContent());
        map.put("parentId", comment.getParentId());
        map.put("createTime", comment.getCreateTime());
        
        // 获取用户信息
        User user = userMapper.selectUserById(comment.getUserId());
        if (user != null) {
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("id", user.getId());
            userMap.put("username", user.getUsername());
            userMap.put("nickname", user.getNickname());
            userMap.put("avatar", user.getAvatar());
            map.put("user", userMap);
        }
        
        return map;
    }
    
    /**
     * 清除文章评论相关缓存
     */
    private void clearArticleCommentCache(Integer articleId, Integer commentId, Integer parentId) {
        if (articleId != null) {
            // 清除文章所有评论缓存
            redisUtil.delete(ARTICLE_COMMENT_KEY + "article:" + articleId);
            // 清除文章一级评论缓存
            redisUtil.delete(ARTICLE_ROOT_COMMENT_KEY + articleId);
            // 清除评论树缓存
            redisUtil.delete(ARTICLE_COMMENT_TREE_KEY + articleId);
            // 清除评论数量缓存
            redisUtil.delete(ARTICLE_COMMENT_COUNT_KEY + articleId);
            // 清除分页缓存
            redisUtil.deleteByPattern(ARTICLE_COMMENT_KEY + "page:" + articleId + ":*");
            
            // 清除包含该文章ID的批量根评论缓存和批量评论树缓存
            redisUtil.deleteByPattern(ARTICLE_COMMENT_KEY + "batch:root:*");
            redisUtil.deleteByPattern(ARTICLE_COMMENT_TREE_KEY + "batch:*");
        }
        
        if (commentId != null) {
            // 清除评论详情缓存
            redisUtil.delete(ARTICLE_COMMENT_KEY + "id:" + commentId);
            // 清除评论回复缓存
            redisUtil.delete(ARTICLE_COMMENT_KEY + "replies:" + commentId);
        }
        
        if (parentId != null && parentId > 0) {
            // 清除父评论的回复缓存
            redisUtil.delete(ARTICLE_COMMENT_KEY + "replies:" + parentId);
        }
        
        // 由于用户可能查看自己的评论列表，所以这里不清除用户评论缓存
        // 这样处理是为了减少缓存失效的频率，提高性能
        // 用户评论列表缓存会在过期时间后自动失效，或者在用户查询自己评论列表时重新生成
    }

    /**
     * 批量获取多篇文章的根评论
     * 针对文章列表页优化，一次性获取多篇文章的评论
     *
     * @param articleIds 文章ID列表
     * @return 文章ID与其根评论列表的映射
     */
    public Map<Integer, List<ArticleComment>> getBatchRootComments(List<Integer> articleIds) {
        if (articleIds == null || articleIds.isEmpty()) {
            return new HashMap<>();
        }
        
        // 构建缓存键，包含文章ID列表的哈希值
        String articleIdsStr = articleIds.stream()
                .sorted()
                .map(String::valueOf)
                .collect(Collectors.joining("-"));
        String cacheKey = ARTICLE_COMMENT_KEY + "batch:root:" + articleIdsStr.hashCode();
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<Integer, List<ArticleComment>>) cached;
        }
        
        // 缓存未命中，需要查询每篇文章的评论
        Map<Integer, List<ArticleComment>> result = new HashMap<>();
        
        // 这里可以改为批量查询，但为了复用已有的缓存机制，我们使用循环单独查询
        for (Integer articleId : articleIds) {
            List<ArticleComment> comments = getRootCommentsByArticleId(articleId);
            result.put(articleId, comments);
        }
        
        // 将结果存入缓存，设置较短的过期时间
        redisUtil.set(cacheKey, result, 600); // 10分钟缓存
        
        return result;
    }

    /**
     * 批量获取多篇文章的评论树
     * 针对文章列表页优化，一次性获取多篇文章的评论树
     *
     * @param articleIds 文章ID列表
     * @return 文章ID与其评论树的映射
     */
    public Map<Integer, List<Map<String, Object>>> getBatchCommentTrees(List<Integer> articleIds) {
        if (articleIds == null || articleIds.isEmpty()) {
            return new HashMap<>();
        }
        
        // 构建缓存键，包含文章ID列表的哈希值
        String articleIdsStr = articleIds.stream()
                .sorted()
                .map(String::valueOf)
                .collect(Collectors.joining("-"));
        String cacheKey = ARTICLE_COMMENT_TREE_KEY + "batch:" + articleIdsStr.hashCode();
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<Integer, List<Map<String, Object>>>) cached;
        }
        
        // 缓存未命中，需要查询每篇文章的评论树
        Map<Integer, List<Map<String, Object>>> result = new HashMap<>();
        
        // 复用已有的获取评论树方法
        for (Integer articleId : articleIds) {
            List<Map<String, Object>> commentTree = getCommentTree(articleId);
            result.put(articleId, commentTree);
        }
        
        // 将结果存入缓存，设置较短的过期时间
        redisUtil.set(cacheKey, result, 600); // 10分钟缓存
        
        return result;
    }

    /**
     * 批量获取多篇文章的评论数量
     * 针对文章列表页优化，一次性获取多篇文章的评论数
     *
     * @param articleIds 文章ID列表
     * @return 文章ID与其评论数的映射
     */
    public Map<Integer, Integer> getBatchArticleCommentCounts(List<Integer> articleIds) {
        if (articleIds == null || articleIds.isEmpty()) {
            return new HashMap<>();
        }
        
        // 构建缓存键，包含文章ID列表的哈希值
        String articleIdsStr = articleIds.stream()
                .sorted()
                .map(String::valueOf)
                .collect(Collectors.joining("-"));
        String cacheKey = ARTICLE_COMMENT_COUNT_KEY + "batch:" + articleIdsStr.hashCode();
        
        // 尝试从缓存获取
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return (Map<Integer, Integer>) cached;
        }
        
        // 缓存未命中，需要查询每篇文章的评论数
        Map<Integer, Integer> result = new HashMap<>();
        
        // 这里可以改为批量查询，但为了复用已有的缓存机制，我们使用循环单独查询
        for (Integer articleId : articleIds) {
            int count = countCommentsByArticleId(articleId);
            result.put(articleId, count);
        }
        
        // 将结果存入缓存，设置较短的过期时间
        redisUtil.set(cacheKey, result, 600); // 10分钟缓存
        
        return result;
    }
} 